from __future__ import division

from math import *
import random
from pygame import Color as Colour
from OpenGL.GL import *

try:
	from psyco.classes import *
except ImportError:
	pass

class Terrain(object):
	def __init__(self):
		glEnable(GL_COLOR_MATERIAL)
		glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)
		glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, 1)
		
		glEnable(GL_LIGHTING)
		glEnable(GL_LIGHT0)
		
		self.light_diffuse = (1, 1, 1, 1)
		self.light_ambient = (1, 1, 1, 1)
		self.light_specular = (1, 1, 1, 1)
		self.light_position = (-640, 240, -640, 0)
		
		self.side_colour = (0.5, 0, 0, 1)
		self.side_specular = (0, 0, 0, 1)
		self.side_emission = (0, 0, 0, 1)
	
	def light_setup(self):
		glLightfv(GL_LIGHT0, GL_DIFFUSE, self.light_diffuse)
		glLightfv(GL_LIGHT0, GL_AMBIENT, self.light_ambient)
		glLightfv(GL_LIGHT0, GL_SPECULAR, self.light_specular)
		glLightfv(GL_LIGHT0, GL_POSITION, self.light_position)
	
	def update(self, eye):
		pass
	
	def surface(self, centre, incline):
		return (1, 1, 1, 1), (0, 0, 0, 1), (0, 0, 0, 1)

class Basic(Terrain):
	def __init__(self):
		super(Basic, self).__init__()
		
		ldirect = .50
		self.light_diffuse = (ldirect, ldirect, ldirect, 1)
		self.light_ambient = (1-ldirect, 1-ldirect, 1-ldirect, 1)
		
		colour = Colour(0, 0, 0, 1)
		colour.hsva = (27/255 * 360, 78/255 * 100, 65, 1)
		self.side_colour = colour.normalize()
	
	def surface(self, centre, incline):
		height = centre[2]
	
		if incline < radians(45):
			h, s = 89/255, 69/255
		elif incline < radians(70):
			h, s = 27/255, 78/255
		else:
			h, s = 237/255, 9/255
	
		light = 0.75	
		colour = Colour(0, 0, 0, 0)
		colour.hsva = (h * 360, s * 100, light * 100, 100)
		specular = (0, 0, 0, 1)
		emission = (0, 0, 0, 1)
	
		return colour.normalize(), specular, emission

class Temperate(Terrain):
	def __init__(self):
		super(Temperate, self).__init__()
		
		ldirect = .50
		self.light_diffuse = (ldirect, ldirect, ldirect, 1)
		self.light_ambient = (1-ldirect, 1-ldirect, 1-ldirect, 1)
		
		colour = Colour(0, 0, 0, 1)
		colour.hsva = (27/255 * 360, 78/255 * 100, 65, 1)
		self.side_colour = colour.normalize()
	
	def surface(self, centre, incline):
		incline = degrees(incline)

		height = centre[2]

		h1, s1 = 0.349, 0.270 #h1, s1 = 89/255, 69/255
		h2, s2 = 0.106, 0.306 #h2, s2 = 27/255, 78/255
		h3, s3 = 0.106, 0.000 #h3, s3 = 27/255, 0/255
	
		b1=27
		b2=50
		b3=70

		if incline < b1:
			h=h1
			s=s1
		elif incline < b2:
			p = (incline-b1)/(b2-b1)
			h = ((1-p)*h1)+(p*h2)
			s = ((1-p)*s1)+(p*s2)
		elif incline < b3:
			p = (incline-b2)/(b3-b2)
			h = ((1-p)*h2)+(p*h3)
			s = ((1-p)*s2)+(p*s3)
		else:
			h=h3
			s=s3
		
		light = 0.65
	
		colour = Colour(0, 0, 0, 0)
		colour.hsva = (h * 360, s * 100, max(0,min(1,light - .03 + .0015*height)) * 100, 100)
		specular = (0, 0, 0, 1)
		emission = (0, 0, 0, 1)
	
		return colour.normalize(), specular, emission

class Lunar(Terrain):
	def __init__(self):
		super(Lunar, self).__init__()
		
		ldirect = 1
		self.light_diffuse = (ldirect, ldirect, ldirect, 1) #(0,0,0,1) #
		self.light_ambient = (1-ldirect, 1-ldirect, 1-ldirect, 1)
		
		colour = Colour(0, 0, 0, 1)
		colour.hsva = (320, 5, 65, 1)
		self.side_colour = colour.normalize()
		
		self.backlight1 = (0,0,0,0)
		self.backlight2 = (0,0,0,0)
		self.backlight3 = (0,0,0,0)
		self.backlight4 = (0,0,0,0)
		
		glEnable(GL_LIGHT1)
		glEnable(GL_LIGHT2)
		glEnable(GL_LIGHT3)
		glEnable(GL_LIGHT4)
				
		bcol = (0.3,0.3,0.375,1)#(0.8,0.8,1,1)(0.1,0.1,0.125,1)#
		glLightfv(GL_LIGHT1, GL_DIFFUSE, bcol)
		glLightfv(GL_LIGHT2, GL_DIFFUSE, bcol)
		glLightfv(GL_LIGHT3, GL_DIFFUSE, bcol)
		glLightfv(GL_LIGHT4, GL_DIFFUSE, bcol)
	
	def surface(self, centre, incline):
		incline = degrees(incline)

		height = centre[2]
	
		light = 0.45
	
		colour = Colour(0, 0, 0, 0)
		colour.hsva = (320, 5, max(0,min(1,light - .05 + .0025*height)) * 100, 100) #(320,5,50,100) #
		specular = (0, 0, 0, 1)
		emission = (0, 0, 0, 1)
	
		return colour.normalize(), specular, emission

	def light_setup(self):
		super(Lunar, self).light_setup()
		
		glLightfv(GL_LIGHT1, GL_POSITION, self.backlight1)
		glLightfv(GL_LIGHT2, GL_POSITION, self.backlight2)
		glLightfv(GL_LIGHT3, GL_POSITION, self.backlight3)
		glLightfv(GL_LIGHT4, GL_POSITION, self.backlight4)
		
		glLightfv(GL_LIGHT1, GL_SPECULAR, (0, 0, 0, 1))
		glLightfv(GL_LIGHT2, GL_SPECULAR, (0, 0, 0, 1))
		glLightfv(GL_LIGHT3, GL_SPECULAR, (0, 0, 0, 1))
		glLightfv(GL_LIGHT4, GL_SPECULAR, (0, 0, 0, 1))
		
	def update(self, eye):
		dist = 100
		psin = sin(radians(self.angle-90))
		pcos = cos(radians(self.angle-90))
		self.backlight1 = ( (eye[0])*dist +(pcos*(dist*1.5)) ,(eye[1])*dist +(psin*(dist*1.5)),(eye[2])*dist)
		self.backlight2 = ( (eye[0])*dist -(pcos*(dist*1.5)) ,(eye[1])*dist -(psin*(dist*1.5)),(eye[2])*dist)
		self.backlight3 = ( (eye[0])*dist,(eye[1])*dist,((eye[2])*dist)+(dist*1.2))
		self.backlight4 = ( (eye[0])*dist,(eye[1])*dist,((eye[2])*dist)-(dist*1.2))
		
class Desert(Terrain):
	def __init__(self):
		super(Desert, self).__init__()
		
		ldirect = .85
		brighten = 1.2
		self.light_diffuse = (ldirect*brighten, ldirect*brighten, ldirect*brighten, 1)
		self.light_ambient = (1-ldirect, 1-ldirect, 1-ldirect, 1)
		
		colour = Colour(185, 175, 165, 1)
		self.side_colour = colour.normalize()
	
	def surface(self, centre, incline):
		incline = degrees(incline)
		
		height = centre[2]
		
		maxsand = min(1,( 1.2 - (random.random()*0.35) ) )
		
		sand  = ( 230, 215, 160 )
		rock1 = ( 185, 175, 165 )
		rock2 = ( 200, 165, 150 )
		rock3 = ( 155, 150, 140 )
		
		r,g,b = 0,0,0
		
		#height 0-156
		strata = (
		(0, rock1),
		(30, rock2),
		(45, rock3),
		(60, rock2),
		(75, rock3),
		(105, rock1),
		(120, rock2),
		(135, rock1),
		(150, rock3)
		)
		
		for i in xrange(0,len(strata)-1):
			if height >= strata[i][0]:
				r,g,b = strata[i][1]

		mix = (1-(min(incline,60)/60))*maxsand
		
		r,g,b = (r*(1-mix))+(sand[0]*mix), (g*(1-mix))+(sand[1]*mix), (b*(1-mix))+(sand[2]*mix)
	
		light = 1.00
			
		colour = Colour(int(r*light), int(g*light), int(b*light), 255)
		specular = (0, 0, 0, 1)
		emission = (0, 0, 0, 1)
	
		return colour.normalize(), specular, emission
		
class Insanity(Terrain):
	def __init__(self):
		super(Insanity, self).__init__()
		
		self.light_diffuse = (random.random(), random.random(), random.random(), random.random())
		self.light_ambient = (random.random(), random.random(), random.random(), random.random())
		self.side_colour = (random.random(), random.random(), random.random(), random.random())
	
	def surface(self, centre, incline):
		colour = (random.random(), random.random(), random.random(), random.random())
		specular = (random.random(), random.random(), random.random(), random.random())
		emission = (random.random(), random.random(), random.random(), random.random())
	
		return colour, specular, emission

class Passability(Terrain):
	def __init__(self):
		super(Passability, self).__init__()
		
		ldirect = .50
		self.light_diffuse = (ldirect, ldirect, ldirect, 1)
		self.light_ambient = (1-ldirect, 1-ldirect, 1-ldirect, 1)
		
		colour = Colour(0, 0, 0, 1)
		colour.hsva = (27/255 * 360, 78/255 * 100, 65, 1)
		self.side_colour = colour.normalize()
	
	def surface(self, centre, incline):
		height = centre[2]
	
		if 9.8 * 1000 * sin(incline) <= 5650:
			colour = (0, 0.75, 0, 1)
		else:
			colour = (0.75, 0, 0, 1)
		
		specular = (0, 0, 0, 1)
		emission = (0, 0, 0, 1)
	
		return colour, specular, emission

nostalgiamode = Basic
standardmode = Temperate
moonmode = Lunar
arkofthecovenantmode = Insanity
scorchiomode = Desert
christmasmode = Passability

TERRAINS = {
	None: None,
	"temperate": Temperate,
	"lunar": Lunar,
	"basic": Basic,
	"insanity": Insanity,
	"passability": Passability,
	"desert": Desert}
